package com.example.redislearning.service.impl;

import com.example.redislearning.entity.Course;
import com.example.redislearning.mapper.CourseMapper;
import com.example.redislearning.service.CartService;
import com.example.redislearning.util.RedisKeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 购物车服务实现类
 * 基于Redis的购物车功能实现
 * 支持用户登录/未登录状态下的购物车管理
 */
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private CourseMapper courseMapper;

    // 购物车有效期：7天
    private static final Integer CART_EXPIRE_DAYS = 7;

    /**
     * 添加商品到购物车
     *
     * @param userId   用户ID
     * @param courseId 课程ID
     * @param quantity 添加数量
     * @return 是否添加成功
     */
    @Override
    public boolean addToCart(Integer userId, Integer courseId, Integer quantity) {
        try {
            String cartKey = RedisKeyUtil.getCartKey(userId);
            String cartItemKey = String.valueOf(courseId);

            // 检查课程是否存在且有效
            Course course = courseMapper.selectById(courseId);
            if (course == null || course.getStatus() != 1) {
                return false;
            }

            // 获取当前购物车商品数量
            Object existingQuantity = redisTemplate.opsForHash().get(cartKey, cartItemKey);
            int newQuantity = quantity;
            if (existingQuantity != null) {
                newQuantity += Integer.parseInt(existingQuantity.toString());
            }

            // 限制单个商品最大数量
            if (newQuantity > 10) {
                newQuantity = 10;
            }

            // 添加到购物车
            redisTemplate.opsForHash().put(cartKey, cartItemKey, newQuantity);

            // 设置购物车过期时间
            redisTemplate.expire(cartKey, CART_EXPIRE_DAYS, TimeUnit.DAYS);

            // 更新购物车商品总数
            updateCartItemCount(userId);

            return true;
        } catch (Exception e) {
            throw new RuntimeException("添加到购物车失败", e);
        }
    }

    /**
     * 从购物车移除商品
     *
     * @param userId   用户ID
     * @param courseId 课程ID
     * @return 是否移除成功
     */
    @Override
    public boolean removeFromCart(Integer userId, Integer courseId) {
        try {
            String cartKey = RedisKeyUtil.getCartKey(userId);
            String cartItemKey = String.valueOf(courseId);

            Long result = redisTemplate.opsForHash().delete(cartKey, cartItemKey);

            if (result > 0) {
                // 更新购物车商品总数
                updateCartItemCount(userId);
                return true;
            }

            return false;
        } catch (Exception e) {
            throw new RuntimeException("从购物车移除失败", e);
        }
    }

    /**
     * 更新购物车商品数量
     *
     * @param userId   用户ID
     * @param courseId 课程ID
     * @param quantity 新的数量，如果小于等于0则移除商品
     * @return 是否更新成功
     */
    @Override
    public boolean updateCartItemQuantity(Integer userId, Integer courseId, Integer quantity) {
        try {
            if (quantity <= 0) {
                return removeFromCart(userId, courseId);
            }

            String cartKey = RedisKeyUtil.getCartKey(userId);
            String cartItemKey = String.valueOf(courseId);

            // 检查课程是否存在
            Course course = courseMapper.selectById(courseId);
            if (course == null || course.getStatus() != 1) {
                return false;
            }

            // 限制最大数量
            if (quantity > 10) {
                quantity = 10;
            }

            redisTemplate.opsForHash().put(cartKey, cartItemKey, quantity);
            redisTemplate.expire(cartKey, CART_EXPIRE_DAYS, TimeUnit.DAYS);

            // 更新购物车商品总数
            updateCartItemCount(userId);

            return true;
        } catch (Exception e) {
            throw new RuntimeException("更新购物车商品失败", e);
        }
    }

    /**
     * 获取用户购物车中的所有商品
     *
     * @param userId 用户ID
     * @return 包含商品列表、总价、商品总数等信息的Map对象
     */
    @Override
    public Map<String, Object> getCartItems(Integer userId) {
        try {
            String cartKey = RedisKeyUtil.getCartKey(userId);

            // 获取购物车中所有商品
            Map<Object, Object> cartItems = redisTemplate.opsForHash().entries(cartKey);

            if (cartItems.isEmpty()) {
                return new HashMap<>();
            }

            // 获取课程信息
            List<Integer> courseIds = new ArrayList<>();
            Map<String, Integer> quantities = new HashMap<>();

            for (Map.Entry<Object, Object> entry : cartItems.entrySet()) {
                Integer courseId = Integer.valueOf(entry.getKey().toString());
                Integer quantity = Integer.parseInt(entry.getValue().toString());
                courseIds.add(courseId);
                quantities.put(courseId.toString(), quantity);
            }

            List<Course> courses = courseMapper.selectByIds(courseIds);

            // 构建响应数据
            Map<String, Object> result = new HashMap<>();
            List<Map<String, Object>> items = new ArrayList<>();
            double totalPrice = 0.0;
            int totalItems = 0;

            for (Course course : courses) {
                if (course != null && course.getStatus() == 1) {
                    Integer quantity = quantities.get(course.getId().toString());
                    if (quantity != null && quantity > 0) {
                        Map<String, Object> item = new HashMap<>();
                        item.put("course", course);
                        item.put("quantity", quantity);

                        double itemPrice = course.getPrice() * quantity;
                        item.put("itemPrice", itemPrice);

                        items.add(item);
                        totalPrice += itemPrice;
                        totalItems += quantity;
                    }
                }
            }

            result.put("items", items);
            result.put("totalPrice", totalPrice);
            result.put("totalItems", totalItems);
            result.put("userId", userId);

            return result;
        } catch (Exception e) {
            throw new RuntimeException("获取购物车失败", e);
        }
    }

    /**
     * 获取购物车详情列表
     *
     * @param userId 用户ID
     * @return 购物车商品详情列表，每个Map包含课程信息和数量
     */
    @Override
    public List<Map<String, Object>> getCartDetails(Integer userId) {
        try {
            Map<String, Object> cartItems = getCartItems(userId);
            List<Map<String, Object>> items = (List<Map<String, Object>>) cartItems.get("items");
            return items != null ? items : new ArrayList<>();
        } catch (Exception e) {
            throw new RuntimeException("获取购物车详情失败", e);
        }
    }

    /**
     * 清空用户购物车
     *
     * @param userId 用户ID
     * @return 是否清空成功
     */
    @Override
    public boolean clearCart(Integer userId) {
        try {
            String cartKey = RedisKeyUtil.getCartKey(userId);
            redisTemplate.delete(cartKey);

            // 清除购物车商品总数
            String countKey = RedisKeyUtil.getCartItemCountKey(userId);
            redisTemplate.delete(countKey);

            return true;
        } catch (Exception e) {
            throw new RuntimeException("清空购物车失败", e);
        }
    }

    /**
     * 获取用户购物车中的商品总数
     *
     * @param userId 用户ID
     * @return 购物车中的商品总数
     */
    @Override
    public Integer getCartItemCount(Integer userId) {
        try {
            String countKey = RedisKeyUtil.getCartItemCountKey(userId);
            Object count = redisTemplate.opsForValue().get(countKey);

            if (count != null) {
                return Integer.parseInt(count.toString());
            }

            // 如果计数器不存在，重新计算
            String cartKey = RedisKeyUtil.getCartKey(userId);
            Map<Object, Object> cartItems = redisTemplate.opsForHash().entries(cartKey);

            int totalCount = 0;
            for (Map.Entry<Object, Object> entry : cartItems.entrySet()) {
                totalCount += Integer.parseInt(entry.getValue().toString());
            }

            if (totalCount > 0) {
                redisTemplate.opsForValue().set(countKey, totalCount, CART_EXPIRE_DAYS, TimeUnit.DAYS);
            }

            return totalCount;
        } catch (Exception e) {
            throw new RuntimeException("获取购物车商品数量失败", e);
        }
    }

    /**
     * 获取购物车总价
     *
     * @param userId 用户ID
     * @return 购物车中所有商品的总价格
     */
    @Override
    public Double getCartTotalPrice(Integer userId) {
        try {
            Map<String, Object> cartItems = getCartItems(userId);
            BigDecimal totalPrice = (BigDecimal) cartItems.get("totalPrice");
            return totalPrice != null ? totalPrice.doubleValue() : 0.0;
        } catch (Exception e) {
            throw new RuntimeException("获取购物车总价失败", e);
        }
    }

    /**
     * 批量添加商品到购物车
     *
     * @param userId 用户ID
     * @param items  商品ID和数量的Map集合
     * @return 是否全部添加成功
     */
    @Override
    public boolean batchAddToCart(Integer userId, Map<Integer, Integer> items) {
        try {
            if (items == null || items.isEmpty()) {
                return true;
            }

            boolean allSuccess = true;
            for (Map.Entry<Integer, Integer> entry : items.entrySet()) {
                boolean result = addToCart(userId, entry.getKey(), entry.getValue());
                if (!result) {
                    allSuccess = false;
                }
            }

            return allSuccess;
        } catch (Exception e) {
            throw new RuntimeException("批量添加购物车失败", e);
        }
    }

    /**
     * 批量移除购物车中的商品
     *
     * @param userId    用户ID
     * @param courseIds 要移除的课程ID列表
     * @return 是否成功移除至少一个商品
     */
    @Override
    public boolean batchRemoveFromCart(Integer userId, List<Integer> courseIds) {
        try {
            if (courseIds == null || courseIds.isEmpty()) {
                return true;
            }

            String cartKey = RedisKeyUtil.getCartKey(userId);
            String[] courseIdStrings = courseIds.stream()
                    .map(String::valueOf)
                    .toArray(String[]::new);

            Long result = redisTemplate.opsForHash().delete(cartKey, (Object[]) courseIdStrings);

            if (result > 0) {
                updateCartItemCount(userId);
            }

            return result > 0;
        } catch (Exception e) {
            throw new RuntimeException("批量移除购物车商品失败", e);
        }
    }

    /**
     * 合并临时购物车到用户购物车
     *
     * @param userId        用户ID
     * @param tempCartItems 临时购物车商品ID和数量的Map集合
     * @return 是否合并成功
     */
    @Override
    public boolean mergeCart(Integer userId, Map<Integer, Integer> tempCartItems) {
        try {
            if (tempCartItems == null || tempCartItems.isEmpty()) {
                return true;
            }

            for (Map.Entry<Integer, Integer> entry : tempCartItems.entrySet()) {
                addToCart(userId, entry.getKey(), entry.getValue());
            }

            return true;
        } catch (Exception e) {
            throw new RuntimeException("合并购物车失败", e);
        }
    }

    /**
     * 检查商品是否在购物车中
     *
     * @param userId   用户ID
     * @param courseId 课程ID
     * @return 商品是否在购物车中
     */
    @Override
    public boolean isInCart(Integer userId, Integer courseId) {
        try {
            String cartKey = RedisKeyUtil.getCartKey(userId);
            return redisTemplate.opsForHash().hasKey(cartKey, String.valueOf(courseId));
        } catch (Exception e) {
            throw new RuntimeException("检查购物车失败", e);
        }
    }

    /**
     * 获取购物车中无效的商品列表
     *
     * @param userId 用户ID
     * @return 无效商品ID和数量的Map集合，无效商品包括已下架或删除的课程
     */
    @Override
    public Map<Integer, Integer> getInvalidCartItems(Integer userId) {
        try {
            String cartKey = RedisKeyUtil.getCartKey(userId);
            Map<Object, Object> cartItems = redisTemplate.opsForHash().entries(cartKey);

            Map<Integer, Integer> invalidItems = new HashMap<>();

            for (Map.Entry<Object, Object> entry : cartItems.entrySet()) {
                Integer courseId = Integer.valueOf(entry.getKey().toString());
                Integer quantity = Integer.parseInt(entry.getValue().toString());

                // 检查课程是否有效
                Course course = courseMapper.selectById(courseId);
                if (course == null || course.getStatus() != 1) {
                    invalidItems.put(courseId, quantity);
                }
            }

            return invalidItems;
        } catch (Exception e) {
            throw new RuntimeException("获取无效购物车商品失败", e);
        }
    }

    /**
     * 移除购物车中无效的商品
     *
     * @param userId 用户ID
     * @return 是否成功移除所有无效商品
     */
    @Override
    public boolean removeInvalidItems(Integer userId) {
        try {
            Map<Integer, Integer> invalidItems = getInvalidCartItems(userId);

            for (Integer courseId : invalidItems.keySet()) {
                removeFromCart(userId, courseId);
            }

            return true;
        } catch (Exception e) {
            throw new RuntimeException("移除无效购物车商品失败", e);
        }
    }

    /**
     * 更新购物车商品总数
     */
    private void updateCartItemCount(Integer userId) {
        try {
            String cartKey = RedisKeyUtil.getCartKey(userId);
            String countKey = RedisKeyUtil.getCartItemCountKey(userId);

            Map<Object, Object> cartItems = redisTemplate.opsForHash().entries(cartKey);
            int totalCount = 0;

            for (Map.Entry<Object, Object> entry : cartItems.entrySet()) {
                totalCount += Integer.parseInt(entry.getValue().toString());
            }

            if (totalCount > 0) {
                redisTemplate.opsForValue().set(countKey, totalCount, CART_EXPIRE_DAYS, TimeUnit.DAYS);
            } else {
                redisTemplate.delete(countKey);
            }
        } catch (Exception e) {
            throw new RuntimeException("更新购物车商品总数失败", e);
        }
    }
}